package com.plugin.buildsrc

import com.android.build.gradle.AppExtension
import com.android.build.gradle.AppPlugin
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.ApplicationVariant
import com.android.build.gradle.api.LibraryVariant
import com.android.build.gradle.internal.api.ApkVariantOutputImpl
import com.android.build.gradle.internal.dsl.BaseFlavor
import com.android.build.gradle.internal.errors.DeprecationReporterImpl
import com.android.build.gradle.internal.errors.SyncIssueReporterImpl
import com.android.build.gradle.internal.lint.LintFromMaven
import com.android.build.gradle.internal.scope.ProjectInfo
import com.android.build.gradle.internal.services.DslServices
import com.android.build.gradle.internal.services.DslServicesImpl
import com.android.build.gradle.internal.services.ProjectServices
import com.android.build.gradle.options.ProjectOptionService
import com.android.build.gradle.options.ProjectOptions
import com.android.build.gradle.options.SyncOptions
import com.android.builder.core.AbstractProductFlavor
import com.android.builder.model.ProductFlavor
import com.google.gson.Gson
import com.iqiyi.qigsaw.buildtool.gradle.internal.tool.AGPCompat
import com.plugin.buildsrc.module.GenerateOriginModuleInfo
import com.plugin.buildsrc.module.ModuleConfig
import org.apache.commons.io.FileUtils
import org.gradle.api.*
import com.plugin.buildsrc.config.VariantBuildConfiguration
import com.plugin.buildsrc.packing.ApkPackingTask

/**Everything For Easy compiling
 Only used by RootProject
 @Author Damon
 */

class PluginForEasy implements Plugin<Project> {
    private final static String prefix_Module = 'm_'

    @Override
    void apply(Project rootProject) {
        System.out.println("插件启动")
        if (rootProject != rootProject.getRootProject()) {
            throw new RuntimeException("${PluginForEasy.name} 只能在根工程build.gradle使用")
        }
        println(rootProject.getGradle().getStartParameter().getTaskRequests())
        rootProject.getGradle().addListener(new TimesCostWatcher())
        VariantBuildConfiguration.init(rootProject)
        rootProject.getAllprojects().each {
            if (it == rootProject || it.name == "buildSrc") {
                return
            }
/*
            it.beforeEvaluate { Project pjt ->
                //先配置好 依赖库
                pjt.apply from: pjt.getRootProject().file('dependencies.gradle')
                //主工程
                if (pjt.name == 'app') {
                    pjt.apply plugin: 'com.android.application'
                    pjt.apply plugin: 'dagger.hilt.android.plugin'
                    pjt.apply plugin: 'PluginForArouter'
//                    pjt.apply plugin: 'PluginForQigsaw'
                    // config_Signature(pjt)
                    config_dependencies(pjt)
                }

                if (isSplitModuleProject(pjt)) {
                    //插件模块工程
                    pjt.apply plugin: 'com.android.dynamic-feature'
                    pjt.apply plugin: 'PluginForArouter'
                    pjt.apply plugin: 'com.iqiyi.qigsaw.dynamicfeature'
                    //   config_Signature(pjt)
                    if (getModuleConfig(pjt).isMvpArch) {
                        pjt.apply plugin: 'PluginForMVP'
                    }
                }

                if (isOriginalModuleProject(pjt)) {
                    //常规模块工程
                    pjt.apply plugin: 'com.android.library'
                    pjt.apply plugin: 'PluginForArouter'
                    //pjt.apply plugin: 'PluginForInitialization'
                    if (getModuleConfig(pjt).isMvpArch) {
                        pjt.apply plugin: 'PluginForMVP'
                    }
                }

                if (pjt.name == 'm_account') {
                    pjt.apply plugin: 'dagger.hilt.android.plugin'
                }
            }*/

            it.afterEvaluate { Project pjt -> config_productLine(pjt)
                /*  config_buildType(pjt)
                  //主工程
                  if (pjt.plugins.hasPlugin(AppPlugin)) {
                      //config_ProGuard(pjt)
                      config_compileOptions(pjt)
                      config_ViewBinding(pjt)
                      config_productLine(pjt)
                      config_SpiltsInfo(pjt)
                      config_ModulesInfo(pjt)
                      pjt.apply plugin: 'com.hujiang.android-aspectjx'   //AspectJ
  //                    pjt.tasks.getByName("clean").doFirst {
  //                        String[] processes = "wmic PROCESS where \"name like '%java%' and CommandLine like '%GradleDaemon%'\" get ProcessId".execute().getText().trim().replace("\r", "").split("\n")
  //                        if(processes.length > 2) {
  //                            println("========================clean")
  //                            "taskkill /f /pid ${processes[1]}".execute()
  //                        }
  //                    }
                  }
  
                  //特别的c库, 不是那种服务层库
                  if (pjt.name == 'c_ui' || pjt.name == 'c_tracking') {
                      config_productLine(pjt)
                  }
  
                  //插件模块工程
                  if (isSplitModuleProject(pjt)) {
                      config_compileOptions(pjt)
                      config_ViewBinding(pjt)
                      config_productLine(pjt)
                      //pjt.apply plugin: 'com.hujiang.android-aspectjx'   //AspectJ
                  }
  
                  //常规模块工程
                  if (isOriginalModuleProject(pjt)) {
                      config_compileOptions(pjt)
                      config_ViewBinding(pjt)
                      config_productLine(pjt)
                      //为了打包
                      //pjt.apply plugin: 'com.hujiang.android-aspectjx'   //AspectJ
                  }
  
                  //检查依赖关系
                  DependencyCheck.checkDependency(pjt)*/
            }
        }
    }

    boolean isModuleProject(Project pjt) {
        return pjt.name.startsWith(prefix_Module)
    }

    boolean isOriginalModuleProject(Project pjt) {
        if (isModuleProject(pjt)) {
            return !getModuleConfig(pjt).isSplit
        }
        return false
    }

    boolean isSplitModuleProject(Project pjt) {
        if (isModuleProject(pjt)) {
            return getModuleConfig(pjt).isSplit
        }
        return false
    }

    void config_dependencies(Project appProject) {
        appProject.getRootProject().getAllprojects().each {
            if (it != appProject) {
                if (isOriginalModuleProject(it)) {
                    appProject.getDependencies().invokeMethod("implementation", it)
                } else if (isSplitModuleProject(it)) it.getDependencies().invokeMethod("implementation", appProject)
            }
        }
    }

    //解析 模块工程配置文件
    ModuleConfig getModuleConfig(Project pjt) {
        if (!isModuleProject(pjt)) throw new RuntimeException("${pjt.name} 工程非模块工程, 非法获取Config")
        ModuleConfig config
        try {
            config = pjt.moduleConfig
        } catch (MissingPropertyException exception) {
            File configFile = pjt.file('config.json')
            if (!configFile.exists()) throw new RuntimeException("${pjt.name} 工程缺少config.json, 请补充在路径 ${pjt.projectDir.toString()} 下")
            BufferedReader bufferedReader = configFile.newReader()
            config = new Gson().fromJson(bufferedReader, ModuleConfig)
            pjt.metaClass.moduleConfig = config
            bufferedReader.close()
            bufferedReader = null
        }
        return config
    }

    //主工程 配置常规模块 工程信息
    void config_ModulesInfo(Project appProject) {
        appProject.android.getApplicationVariants().all { ApplicationVariant variant ->
            GenerateOriginModuleInfo generateModuleConfigTask = appProject.tasks.create("generate${variant.name.capitalize()}ModuleConfig", GenerateOriginModuleInfo.class)
            List<String> names = []
            appProject.getRootProject().subprojects.each { Project pjt ->
                if (isOriginalModuleProject(pjt)) {
                    names.add(":$pjt.name".toString())
                }
            }
            generateModuleConfigTask.className = 'ModuleConfig'
            generateModuleConfigTask.outputDir = variant.variantData.scope.buildConfigSourceOutputDir
            generateModuleConfigTask.moduleNames = names
            Task generateBuildConfigTask = AGPCompat.getGenerateBuildConfigTask(appProject, variant.name.capitalize())
            generateBuildConfigTask.finalizedBy generateModuleConfigTask
        }
    }

    //主工程 配置 插件模块 工程信息
    void config_SpiltsInfo(Project appProject) {
        def names = []
        appProject.getRootProject().subprojects.each { Project pjt ->
            if (isSplitModuleProject(pjt)) {
                names.add(":$pjt.name".toString())
            }
        }
        appProject.android.dynamicFeatures.addAll(names)
    }

    //ProGuard文件 配置
    void config_ProGuard(Project project) {
        def release = project.android.buildTypes.release
        project.getRootProject().getAllprojects().each { Project childProject ->
            File file = childProject.file('proguard-rules.pro')
            if (file.exists() && childProject != project) {
                release.proguardFile(childProject.file('proguard-rules.pro'))
            }
        }
    }

    void config_buildType(Project project) {
        try {
            project.android { BaseExtension extension ->
                buildTypes {
                    debug {
                        signingConfig null
                        debuggable true
                    }
                    release {
                        minifyEnabled true
                        debuggable false
                    }
                }
            }
        } catch (Exception e) {

        }
    }

    //配置相应产品线 以切换一些相应产品 代码资源
    void config_productLine(Project project) {
        BaseExtension extension = project.android
        if (extension instanceof AppExtension) {
            ((AppExtension) extension).getApplicationVariants().whenObjectAdded(new Action<ApplicationVariant>() {
                @Override
                void execute(ApplicationVariant variant) {
                    VariantBuildConfiguration.config(project, variant)
                    variant.outputs.all { ApkVariantOutputImpl apkVariantOutput -> apkVariantOutput.outputFileName = "${apkVariantOutput.name}-${apkVariantOutput.getVersionNameOverride()}.apk".replace(" ", "")
                    }
                }
            })

            project.afterEvaluate {
                def platformTasks = new HashMap<String, DefaultTask>()
                project.android.applicationVariants.all { ApplicationVariant variant ->
                    def platformFlavor = variant.productFlavors.find { it.getDimension() == 'platform' }
                    def envFlavor = variant.productFlavors.find { it.getDimension() == 'env' }
                    if (!platformTasks.containsKey(platformFlavor.name)) {
                        platformTasks.put(platformFlavor.name, new ArrayList())
                    }
                    def tasks = platformTasks[platformFlavor.name]
                    tasks.add(project.task("packing${variant.name.capitalize()}", type: ApkPackingTask) {
                        System.out.println(project.getRootProject().rootDir.toURL())
                        System.out.println("outputs:${platformFlavor.name}")
                        System.out.println("versionName:${variant.versionName}")
                        System.out.println("LowerCase：${envFlavor.name.toLowerCase()}")
                        mVariant = variant
                        mOutputDir = project.getRootProject().file("outputs/${platformFlavor.name}/${variant.versionName}/${envFlavor.name.toLowerCase()}")
                        mChannels = platformFlavor.channels
                        Task cleanTask = project.tasks.findByName('clean')
                        dependsOn cleanTask
                        dependsOn variant.getAssembleProvider().get()
                        variant.getAssembleProvider().get().mustRunAfter(cleanTask)
                    })
                }

                platformTasks.each { Map.Entry<String, List<DefaultTask>> entry ->
                    project.task("packing${entry.key.capitalize()}ALLRelease", group: entry.value[0].getGroup(), type: DefaultTask) {
                        dependsOn(entry.value.findAll {
                            it.name.toLowerCase().contains("debug")
                        })
                    }.doFirst {
                        FileUtils.deleteDirectory(project.getRootProject().file("outputs"))
                    }
                }
            }
        } else if (extension instanceof LibraryExtension) {
            ((LibraryExtension) extension).getLibraryVariants().whenObjectAdded(new Action<LibraryVariant>() {
                @Override
                void execute(LibraryVariant variant) {
                    VariantBuildConfiguration.config(project, variant)
                }
            })
        }


        project.android { BaseExtension ext ->
            boolean isApp = ext instanceof AppExtension

            Closure<Properties> configApplicationProperties = { BaseFlavor productFlavor ->
                if (!isApp) return null
                Properties props = new Properties()
                FileInputStream fileInputStream = new FileInputStream(project.getRootProject().file("${productFlavor.name}.properties"))
                props.load(fileInputStream)
                System.out.println("123 : " + project.getRootProject().file("${productFlavor.name}.properties"))

                //如果Project的Properties中有相同的KeyValue, 需要做替换, Jenkins会配置相应的Properties
                props.keySet().each { def key ->
                    String value = project.properties.get(key)
                    if (value != null && !value.isEmpty()) props.put(key, project.properties.get(key))
                }
                productFlavor.versionName = props.get("versionName")
                productFlavor.versionCode = Integer.valueOf(props.get("versionCode"))
                productFlavor.applicationId = props.get("applicationId")
//                DslServicesImpl dslServices =new  DslServicesImpl(
//                        getProjectServices(project),
//                        project.providers.provider { null },null)
                String signFilePath =props.get("signFilePath")
                String keyAlias =props.get("keyAlias")
                String keyPassword =props.get("keyPassword")
                String name =productFlavor.name
                System.out.println(signFilePath)
                System.out.println(keyAlias)
                System.out.println(keyPassword)
                System.out.println(name)
//                productFlavor.signingConfig = new MySigningConfig(props.get("signFilePath"),
//                        true,
//                        true,
//                        false,
//                        false,
//                        props.get("keyAlias"),
//                        props.get("keyPassword"),
//                        props.get("keyPassword"),
//                        "JKS",
//                        productFlavor.name,
//                        dslServices)

//                        .setKeyAlias(props.get("keyAlias"))
//                        .setKeyPassword(props.get("keyPassword"))
//                        .setStorePassword(props.get("keyPassword"))
//                        .setStoreFile(project.rootProject.file(props.get("signFilePath")))
                HashSet<String> channels = new HashSet<>()
                props.get("channels").toString().split(",").each {
                    channels.add(it)
                }
                File extraChannelsFile = project.rootProject.file("channels.txt")
                if (extraChannelsFile.exists()) {
                    extraChannelsFile.readLines().each {
                        channels.add(it)
                    }
                }
                productFlavor.metaClass.channels = channels.toList()
                fileInputStream.close()
            }

            flavorDimensions "platform", "env"
            productFlavors {
                DEV {
                    dimension "env"
                }
                SIT {
                    dimension "env"
                }
                UAT {
                    dimension "env"
                }
                PROD {
                    dimension "env"
                }

                streamingtv {
                    dimension "platform"
                    configApplicationProperties(it)
                    resValue "string", "tray__authority", "${applicationId}.user_preference"
                }
            }
        }
    }

    //ViewBinding
    void config_ViewBinding(Project project) {
        project.android {
            viewBinding {
                enabled = true
            }
        }
    }

    void config_compileOptions(Project project) {
        project.android {
            compileOptions {
                sourceCompatibility JavaVersion.VERSION_1_8
                targetCompatibility JavaVersion.VERSION_1_8
            }
        }
    }

    private ProjectServices getProjectServices(Project project) {
        ProjectOptions projectOptions =
                new ProjectOptionService.RegistrationAction(project)
                        .execute()
                        .get()
                        .getProjectOptions()

        SyncIssueReporterImpl syncIssueHandler =
                new SyncIssueReporterImpl(SyncOptions.getModelQueryMode(projectOptions),
                        SyncOptions.getErrorFormatMode(projectOptions),
                        project.getLogger())

        DeprecationReporterImpl deprecationReporter =
                new DeprecationReporterImpl(syncIssueHandler, projectOptions, project.getPath())
        LintFromMaven lintFromMaven = LintFromMaven.from(project, projectOptions, syncIssueHandler)

        ProjectServices projectServices =
                new ProjectServices(syncIssueHandler,
                        deprecationReporter,
                        project.getObjects(),
                        project.getLogger(),
                        project.getProviders(),
                        project.getLayout(),
                        projectOptions,
                        project.getGradle().getSharedServices(),
                        lintFromMaven,
                        null,
                        project.getGradle().getStartParameter().getMaxWorkerCount(),
                        new ProjectInfo(project),
                        project::file,
                        project.getConfigurations(),
                        project.getDependencies(),
                        project.getExtensions().getExtraProperties())
        return projectServices

    }


//    //签名
//    void config_Signature(Project project) {
//        project.android.signingConfigs {
//            debug {
//                storeFile new File(project.rootProject.projectDir.absolutePath + "/keystore/debug.keystore")
//                storePassword "123456"
//                keyAlias "debugalias"
//                keyPassword "123456"
//            }
//            release {
//                storeFile new File(project.rootProject.projectDir.absolutePath + "/keystore/release.keystore")
//                storePassword "123456"
//                keyAlias "releasealias"
//                keyPassword "123456"
//            }
//        }
//    }
}

